const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
  constructor(executor) {
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledQueues = [];
    this.onRejectedQueues = [];
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);

    try {
      executor(this.resolve, this.reject);
    } catch (e) {
      reject(e);
    }
  }
  resolve(value) {
    setTimeout(() => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onFulfilledQueues.forEach(cb => cb(this.value));
      }
    });
  }
  reject(reason) {
    setTimeout(() => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedQueues.forEach(cb => cb(this.reason));
      }
    });
  }
  then(onFulfilled, onRejected) {
    let newPromise;
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : reason => {
            throw reason;
          };
    if (this.state === FULFILLED) {
      return (newPromise = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }

    if (this.state === REJECTED) {
      return (newPromise = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }

    if (this.state === PENDING) {
      return (newPromise = new MyPromise((resolve, reject) => {
        this.onFulfilledQueues.push(value => {
          try {
            let x = onFulfilled(value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
        this.onRejectedQueues.push(reason => {
          try {
            let x = onRejected(reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }));
    }
  }
  catch(onRejected) {
    return this.then(null, onRejected);
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  console.log(promise2, x);
  if (promise2 === x) {
    return reject(new TypeError('循环引用'));
  }
  let called = false;
  if (x instanceof MyPromise) {
    if (x.state === PENDING) {
      x.then(
        y => {
          resolvePromise(promise2, y, resolve, reject);
        },
        reason => {
          reject(reason);
        },
      );
    }
  } else if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          reason => {
            if (called) return;
            called = true;
            reject(reason);
          },
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(
      new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(22222222);
        }, 2000);
      }),
    );
  }, 2000);
}).then(result => {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(22222222);
    }, 2000);
  });
});

// static all(promises) {
//   return new MyPromise((resolve, reject) => {
//     let done = gen(promises.length, resolve);
//     promises.forEach((promise, index) => {
//       promise.then(value => {
//         done(index, value);
//       }, reject);
//     });
//   });
// }
// static race(promises) {
//   return new MyPromise((resolve, reject) => {
//     promises.forEach((promise, index) => {
//       promise.then(resolve, reject);
//     });
//   });
// }

// static resolve(value) {
//   return new MyPromise(resolve => {
//     resolve(value);
//   });
// }

// static reject(reason) {
//   return new MyPromise((resolve, reject) => {
//     reject(reason);
//   });
// }
// static deferred() {
//   let defer = {};
//   defer.promise = new MyPromise((resolve, reject) => {
//     defer.resolve = resolve;
//     defer.reject = reject;
//   });
//   return defer;
// }
// function gen(length, resolve) {
//   let count = 0;
//   let values = [];
//   return function(i, value) {
//     values[i] = value;
//     if (++count === length) {
//       console.log(values);
//       resolve(values);
//     }
//   };
// }
